package com.zxj.camerapreview;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.MediaConstraints;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

import cn.iotnova.rtc.AudioRecordManager;
import cn.iotnova.opus.utils.OpusRecorderTask;
import cn.iotnova.rtc.Rtcclient;
import cn.iotnova.webrtc.aec.audio.WebRtcAudioManager;

//https://blog.csdn.net/byhook/article/details/84037338
//width:1080,height:2019
//YUV420SP(NV21)
//YUV420P(YV12)

public class NativeSfuActivity extends AppCompatActivity implements SurfaceHolder.Callback, Camera.PreviewCallback {

    private static final String TAG = NativeSfuActivity.class.getName();
    private SurfaceView mSurfaceView;
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private Camera.Parameters mParameters;
    private int camera_status = 0;

    Rtcclient rtcclient = new Rtcclient();

    Button btn_record;


    private String APP_PATH;
    private String APP_RECORDER_FILE_PATH;
    OpusRecorderTask opusRecorderTask = null;
    private String recorderFilePath;
    private String recorderPcmFilePath;
    private String recorderDecodedPcmFilePath;
    private AudioManager audioManager;
    private int permissionRequestCode;

    int width = 640;
    int height = 480;
    //int width = 480;
    //int height = 640;
    //int width = 1080;
    //int height = 2019;
    private Toast toast;



    PeerConnectionFactory peerConnectionFactory;
    private EglBase rootEglBase;
    Context applicationContext;


    private final void toast(String msg) {
        if (toast != null) {
            toast.cancel();
            toast = null;
        }

        toast = Toast.makeText((Context)this, (CharSequence)msg, Toast.LENGTH_LONG);
        toast.show();
    }

    //int bufferSizeInBytes = AudioRecord.getMinBufferSize(AudioRecordManager.sampleRateInHz, AudioRecordManager.channelConfig, AudioFormat.ENCODING_PCM_16BIT);
    int bufferSizeInBytes = AudioRecord.getMinBufferSize(AudioRecordManager.Rate, AudioRecordManager.channelConfig, AudioFormat.ENCODING_PCM_16BIT);



    public void startRecord() {
        //if (true) return;
        new Thread(new Runnable() {
            @Override
            public void run() {
                AudioRecordManager.getInstance(NativeSfuActivity.this, rtcclient).startRecord();
            }
        }).start();

    }

    void peerconnectionFactory() {

        applicationContext = getApplicationContext();
        rootEglBase = EglBase.create();
        //Initialize PeerConnectionFactory globals.
        PeerConnectionFactory.InitializationOptions initializationOptions =
                PeerConnectionFactory.InitializationOptions.builder(applicationContext)
                        .setEnableVideoHwAcceleration(true)
                        .createInitializationOptions();
        PeerConnectionFactory.initialize(initializationOptions);

        //Create a new PeerConnectionFactory instance - using Hardware encoder and decoder.
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        DefaultVideoEncoderFactory defaultVideoEncoderFactory = new DefaultVideoEncoderFactory(
                rootEglBase.getEglBaseContext(),  /* enableIntelVp8Encoder */true,  /* enableH264HighProfile */true);
        DefaultVideoDecoderFactory defaultVideoDecoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext());
        peerConnectionFactory = PeerConnectionFactory.builder()
                .setOptions(options)
                .setVideoEncoderFactory(defaultVideoEncoderFactory)
                .setVideoDecoderFactory(defaultVideoDecoderFactory)
                .createPeerConnectionFactory();
    }

    //https://blog.csdn.net/weixin_43889841/article/details/101750935
    @SuppressLint("NewApi")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sfumain);
        mSurfaceView = (SurfaceView)findViewById(R.id.surfaceView);
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        rtcclient.setSfuActivity(this);

        new Thread(new Runnable() {
            @Override
            public void run() {
                //rtcclient.ConnectToServer(4, bufferSizeInBytes, "192.168.1.6");
                while (true) {
                    rtcclient.ConnectToServerByCfg(4, bufferSizeInBytes, AudioRecordManager.sampleRateInHz, AudioRecordManager.sampleRateInHz, AudioRecordManager.DEFAULT_OPUS_CHANNEL, "192.168.1.4");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        btn_record = findViewById(R.id.btn_record);

        btn_record.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                //AudioRecordManager.getInstance(NativeSfuActivity.this, rtcclient).startRecord();
            }
        });



        audioManager = getSystemService(AudioManager.class);


        //TAG = getClass().getSimpleName();
        //APP_PATH = Environment.getExternalStorageDirectory().toString() + File.separator + "opusaudiodemo" + File.separator;
        APP_PATH = getFilesDir().toString() + File.separator + "opusaudiodemo" + File.separator;
        APP_RECORDER_FILE_PATH = APP_PATH + "recorder_file" + File.separator;

        recorderFilePath = APP_RECORDER_FILE_PATH + "recorder.ops";
        recorderPcmFilePath = APP_RECORDER_FILE_PATH + "recorder.pcm";
        recorderDecodedPcmFilePath = APP_RECORDER_FILE_PATH + "recorderDecoded.pcm";
        permissionRequestCode = 10;
        //AudioRecordManager.getInstance().startRecord("");

//        opusRecorderTask = new OpusRecorderTask(recorderFilePath, recorderPcmFilePath, rtcclient);
//        (new Thread(opusRecorderTask)).start();

        //startRecorder();

        //peerconnectionFactory();

        /*
        init();

        JavaAudioDeviceModule.Builder builder = JavaAudioDeviceModule.builder(this);
        builder.setSamplesReadyCallback(new JavaAudioDeviceModule.SamplesReadyCallback() {
            @Override
            public void onWebRtcAudioRecordSamplesReady(JavaAudioDeviceModule.AudioSamples audioSamples) {

            }
        });
        //AudioDeviceModule audioDeviceModule = builder.createAudioDeviceModule();
        JavaAudioDeviceModule audioDeviceModule = (JavaAudioDeviceModule)builder.createAudioDeviceModule();
        //audioDeviceModule.getNativeAudioDeviceModulePointer();
         */

    }

    private void init() {
        WebRtcAudioManager.getInstance().start(this);
    }

    public void onChangeClick(View view) {
//        PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 360.0f, 0.0F);
        PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofFloat("rotationY", 0.0f, 360.0f, 0.0F);
        PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.5f,1.0f);
        PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.5f,1.0f);
        ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mSurfaceView,  valuesHolder,valuesHolder1,valuesHolder3);
        objectAnimator.setDuration(5000).start();
    }

    public void onSwitchClick(View view) {
        camera_status ^= 1;
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
        }
        mCamera = Camera.open(camera_status);
        try {
            mCamera.setDisplayOrientation(90);
            mCamera.setPreviewDisplay(mSurfaceView.getHolder());
        } catch (IOException e) {
            e.printStackTrace();
        }
        mCamera.startPreview();
    }

    //https://blog.csdn.net/qq_16775897/article/details/101620194
    byte[] frameBuffer;
    @Override
    public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
        Log.e(TAG,"surfaceCreated");
        try {
            frameBuffer = new byte[((width * height) * ImageFormat.getBitsPerPixel(ImageFormat.NV21)) / 8];

            // Open the Camera in preview mode
            mCamera = Camera.open(camera_status);
            Camera.Parameters param = mCamera.getParameters();

            //https://www.jianshu.com/p/f07a42e1dd0a
            List<Camera.Size> listSize = param.getSupportedPreviewSizes();
            for (Camera.Size size : listSize) {
                System.out.println(size.width + "--------------------" + size.height);
            }


            param.setPictureFormat(PixelFormat.JPEG); //Sets the image format for picture 设定相片格式为JPEG，默认为NV21
            //param.setPreviewFormat(ImageFormat.NV21); //Sets the image format for preview picture，默认为NV21
            param.setPreviewFormat(ImageFormat.NV21); //Sets the image format for preview picture，默认为NV21
            //param.setPictureFormat(PixelFormat.RGBA_8888);
            //param.setPictureFormat(PixelFormat.RGB_565);
            //param.setPictureFormat(PixelFormat.YCbCr_420_SP);
            //param.setPreviewSize(width, height);

            param.setPreviewSize(width, height);

            param.setFlashMode(Camera.Parameters.FOCUS_MODE_AUTO);
            if (!Build.MODEL.equals("KORIDY H30")) {
                param.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1连续对焦
            } else {
                param.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            }


            //<-处理变形
            int displayRotation = 0;
            WindowManager windowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
            int rotation = windowManager.getDefaultDisplay().getRotation();
            switch (rotation) {
                case Surface.ROTATION_0:
                    displayRotation = 0;
                    break;
                case Surface.ROTATION_90:
                    displayRotation = 90;
                    break;
                case Surface.ROTATION_180:
                    displayRotation = 180;
                    break;
                case Surface.ROTATION_270:
                    displayRotation = 270;
                    break;
            }
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(0, info);
            int orientation;
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                orientation = (info.orientation - displayRotation + 360) % 360;
            } else {
                orientation = (info.orientation + displayRotation) % 360;
                orientation = (360 - orientation) % 360;
            }

            System.out.println("ImageFormat.getBitsPerPixel(ImageFormat.NV21)): " + ImageFormat.getBitsPerPixel(ImageFormat.NV21));

            //mCamera.addCallbackBuffer(new byte[((640 * 480) * ImageFormat.getBitsPerPixel(ImageFormat.NV21)) / 8]);
            //mCamera.addCallbackBuffer(new byte[((640 * 480) * ImageFormat.getBitsPerPixel(ImageFormat.RGB_565)) / 8]);
            //mCamera.addCallbackBuffer(frameBuffer); //Sets the image format for preview picture，默认为NV21
            //cameral.setPreviewCallbackWithBuffer()方法必须设置addCallbackBuffer(buffers)后onPreviewFrame()方法才会被持续调用

            //mCamera.setPreviewCallbackWithBuffer(this);

            mCamera.setPreviewCallback(this);

            mCamera.setParameters(param);
            mCamera.setDisplayOrientation(orientation);
            mCamera.setPreviewDisplay(surfaceHolder);
            mCamera.startPreview();

            //SendThread();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int format, int width, int height) {
        Log.e(TAG,"surfaceChanged format:"+format+",width:"+width+",height:"+height);
        /*mCamera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                Log.e(TAG,"onAutoFocus success:"+success);
                if (success) {
                    mParameters = mCamera.getParameters();
                    mParameters.setPictureFormat(PixelFormat.JPEG); //图片输出格式
//                    mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);//预览持续发光
                    mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//持续对焦模式
                    mCamera.setParameters(mParameters);
                    mCamera.startPreview();
                    mCamera.cancelAutoFocus();
                }
            }
        });*/
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
        Log.e(TAG,"surfaceDestroyed");
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);   //切换摄像头时Camera is being used after Camera.release() was called
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    volatile boolean isDestroy = false;

    private ReentrantLock imageArrayLock = new ReentrantLock();
    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        if (bytes == null) return;  //System.out.println("onPreviewFrame byte null");
        if (isDestroy) return;
        imageArrayLock.lock();
        rtcclient.SendNV21Image(bytes, width, height, bytes.length);
        imageArrayLock.unlock();

    }



    @Override
    protected void onDestroy() {
        super.onDestroy();
        isDestroy = true;
        WebRtcAudioManager.getInstance().stop();
    }
}